<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  
  <meta name="renderer" content="webkit">
  <meta http-equiv="X-UA-Compatible" content="IE=edge" >
  <link rel="dns-prefetch" href="//litten.me">
  <title>Nginx能为前端开发带来什么？ | Litten的博客</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <meta name="description" content="Nginx那么好，我想去看看。接连逛了两个书城后，我发现并没有Nginx相关的书籍。这就很奇怪！

Nginx，一名网红（网络服务器红人…），就算没有自传和回忆录，争着介绍它的花边新闻也该有吧。
后来找到仅有的一两本书籍，也直接深入到“源码剖析”的阶段。写得并不十分满意，况且我还不需要这些。后来发现了原因，大概是因为“使用太简单了，都不值得出书”。是的，Nginx把纷繁复杂的功能，浓缩成一份简单的">
<meta property="og:type" content="article">
<meta property="og:title" content="Nginx能为前端开发带来什么？">
<meta property="og:url" content="//litten.me/2015/11/03/nginx-in-fe/index.html">
<meta property="og:site_name" content="Litten的博客">
<meta property="og:description" content="Nginx那么好，我想去看看。接连逛了两个书城后，我发现并没有Nginx相关的书籍。这就很奇怪！

Nginx，一名网红（网络服务器红人…），就算没有自传和回忆录，争着介绍它的花边新闻也该有吧。
后来找到仅有的一两本书籍，也直接深入到“源码剖析”的阶段。写得并不十分满意，况且我还不需要这些。后来发现了原因，大概是因为“使用太简单了，都不值得出书”。是的，Nginx把纷繁复杂的功能，浓缩成一份简单的">
<meta property="og:image" content="//litten.me/assets/blogImg/nginx0.jpg">
<meta property="og:image" content="//litten.me/assets/blogImg/nginx1.jpg">
<meta property="og:image" content="//litten.me/assets/blogImg/nginx2.jpg">
<meta property="og:updated_time" content="2016-11-29T15:33:04.000Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Nginx能为前端开发带来什么？">
<meta name="twitter:description" content="Nginx那么好，我想去看看。接连逛了两个书城后，我发现并没有Nginx相关的书籍。这就很奇怪！

Nginx，一名网红（网络服务器红人…），就算没有自传和回忆录，争着介绍它的花边新闻也该有吧。
后来找到仅有的一两本书籍，也直接深入到“源码剖析”的阶段。写得并不十分满意，况且我还不需要这些。后来发现了原因，大概是因为“使用太简单了，都不值得出书”。是的，Nginx把纷繁复杂的功能，浓缩成一份简单的">
<meta name="twitter:image" content="//litten.me/assets/blogImg/nginx0.jpg">
  
    <link rel="alternative" href="/atom.xml" title="Litten的博客" type="application/atom+xml">
  
  
    <link rel="icon" href="/assets/img/favicon.ico">
  
  <link rel="stylesheet" href="/main.css?v=4.0.0.css">
  

</head>

<body>
  <div id="container" q-class="show:isCtnShow">
    <canvas id="anm-canvas" class="anm-canvas"></canvas>
    <div class="left-col" q-class="show:isShow">
      <div class="overlay"></div>
<div class="intrude-less">
	<header id="header" class="inner">
		<a href="/" class="profilepic">
			<img src="/assets/blogImg/litten.png" class="js-avatar">
		</a>

		<hgroup>
		  <h1 class="header-author"><a href="/">Litten</a></h1>
		</hgroup>

		
		<p class="header-subtitle">胆小认生，不易相处</p>
		

		<nav class="header-menu">
			<ul>
			
				<li><a href="/">主页</a></li>
	        
				<li><a href="/photos">相册</a></li>
	        
			</ul>
		</nav>
		<nav class="header-smart-menu">
	        
    		
    			
    			<a data-idx="0" q-on="click: openSlider(e, 'innerArchive')" href="javascript:void(0)">所有文章</a>
    			
    			
            
    			
            
    			
    			<a data-idx="1" q-on="click: openSlider(e, 'aboutme')" href="javascript:void(0)">关于我</a>
    			
    			
            
		</nav>
		<nav class="header-nav">
			<div class="social">
				
					<a class="github" target="_blank" href="https://github.com/litten" title="github"><i class="icon-github"></i></a>
		        
					<a class="weibo" target="_blank" href="http://weibo.com/litten225" title="weibo"><i class="icon-weibo"></i></a>
		        
					<a class="rss" target="_blank" href="/atom.xml" title="rss"><i class="icon-rss"></i></a>
		        
			</div>
		</nav>
	</header>		
</div>

    </div>
    <div class="mid-col" q-class="show:isShow,hide:isShow|isFalse">
      <nav id="mobile-nav">
  	<div class="overlay">
  		<div class="slider-trigger"><i class="icon-sort"></i></div>
  		<h1 class="header-author js-mobile-header hide">Litten</h1>
  	</div>
	<div class="intrude-less">
		<header id="header" class="inner">
			<div class="profilepic">
				<img src="/assets/blogImg/litten.png" class="js-avatar">
			</div>
			<hgroup>
			  <h1 class="header-author">Litten</h1>
			</hgroup>
			
			<p class="header-subtitle">胆小认生，不易相处</p>
			
			<nav class="header-menu">
				<ul>
				
					<li><a href="/">主页</a></li>
		        
					<li><a href="/photos">相册</a></li>
		        
		        
		        	<li><a href="/archives">所有文章</a></li>
		        
				</ul>
			</nav>
			<nav class="header-nav">
				<div class="social">
					
						<a class="github" target="_blank" href="https://github.com/litten" title="github"><i class="icon-github"></i></a>
			        
						<a class="weibo" target="_blank" href="http://weibo.com/litten225" title="weibo"><i class="icon-weibo"></i></a>
			        
						<a class="rss" target="_blank" href="/atom.xml" title="rss"><i class="icon-rss"></i></a>
			        
				</div>
			</nav>
		</header>				
	</div>
</nav>

      <div id="wrapper" class="body-wrap">
        <div class="menu-l">
          <div class="canvas-wrap">
            <canvas data-colors="#eaeaea" data-sectionHeight="100" data-contentId="js-content" id="myCanvas1" class="anm-canvas"></canvas>
          </div>
          <div id="js-content" class="content-ll">
            <article id="post-nginx-in-fe" class="article article-type-post " itemscope itemprop="blogPost">
  <div class="article-inner">
    
      <header class="article-header">
        
  
    <h1 class="article-title" itemprop="name">
      Nginx能为前端开发带来什么？
    </h1>
  

        <a href="/2015/11/03/nginx-in-fe/" class="archive-article-date">
  	<time datetime="2015-11-03T13:30:00.000Z" itemprop="datePublished"><i class="icon-calendar icon"></i>2015-11-03</time>
</a>
      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <p>Nginx那么好，我想去看看。<br>接连逛了两个书城后，我发现并没有Nginx相关的书籍。<br>这就很奇怪！</p>
<p><img src="/assets/blogImg/nginx0.jpg" alt=""></p>
<p>Nginx，一名<strong>网红</strong>（网络服务器红人…），就算没有自传和回忆录，争着介绍它的花边新闻也该有吧。</p>
<p>后来找到仅有的一两本书籍，也直接深入到“源码剖析”的阶段。写得并不十分满意，况且我还不需要这些。<br>后来发现了原因，大概是因为<strong>“使用太简单了，都不值得出书”</strong>。<br>是的，Nginx把纷繁复杂的功能，浓缩成一份简单的配置，极易上手。<br>当它呈现到你面前时，感觉独具匠心。</p>
<a id="more"></a>
<h3 id="Nginx与NodeJs"><a href="#Nginx与NodeJs" class="headerlink" title="Nginx与NodeJs"></a>Nginx与NodeJs</h3><p>（这里的标题有点歧义。此处的NodeJs，皆引申为NodeJs所搭建的服务器。）</p>
<p>有人说，作为一名前端，<strong>我的真爱是NodeJs</strong>。<br>同时也认同，抛去性能之类的比较，单纯从实现的角度，NodeJs编写的服务器也能实现Nginx的各种功能。                </p>
<p>这些我都赞成，但使用Nginx并不意味着抛弃NodeJs。事实上，它们并不冲突，还可以在一起愉快的玩耍。              </p>
<p>在业内，这样的模型已很常见：资源转发，反向代理，静态资源处理，负载均衡，这些事情扔给Nginx来处理，只是几行配置的事情；同时在上游，让NodeJs去处理它最擅长的I/O等事情。               </p>
<p>合理分配各自<strong>擅长</strong>的事情，这样的思路，同样可以运用于前端开发中。                </p>
<p>以前用NodeJs几百行实现的服务器功能，在npm与github的海洋里花尽心思去寻找的模块，也许在Nginx里是一条成熟的配置。它能帮其分担很多事情，节约了成本。                  </p>
<h3 id="场景一：环境切换"><a href="#场景一：环境切换" class="headerlink" title="场景一：环境切换"></a>场景一：环境切换</h3><p>前端开发中，经常面临多个部署环境切换的问题。<br>我们通常用配hosts的方式去实现。更优化些，我们将机器的服务绑定了不同的域名：比如正式环境是a.qq.com，测试环境是test.a.qq.com。 </p>
<p>然而在拓展性和易用性方面，还不足够好。<br>而Nginx作为反向代理，就很容易处理资源转发的问题。                 </p>
<p>思路很简单：</p>
<blockquote>
<ol>
<li>读取请求里的cookie，如果键名host_id有值，则代理到这个IP地址；</li>
<li>如果没有，则代理到默认的正式环境（此处举例为1.1.1.1）;</li>
</ol>
</blockquote>
<figure class="highlight gams"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">set</span> $env_id <span class="comment">"1.1.1.1"</span>;</div><div class="line"><span class="keyword">if</span> ( <span class="symbol">$</span>http_cookie ~* <span class="string">"host_id=(\S+)(;.*|$)"</span>) &#123;</div><div class="line">    <span class="keyword">set</span> $env_id <span class="comment">$1</span>;</div><div class="line">&#125;</div><div class="line"></div><div class="line">location / &#123;</div><div class="line">    proxy_set_header Host <span class="symbol">$</span>host;</div><div class="line">    proxy_pass   http:<span class="comment">//$env_id:80;</span></div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>那接下来的事情，就是<strong>怎样用最简便的方式，把IP种在cookie里？</strong><br>我们应用了nginx-http-footer-filter模块，html文件经过代理时，都注入了一小段js代码。</p>
<p>这段代码，会帮我们展示小菜单，点击某个环境时，则将IP种到cookie里，同时刷新页面，让Nginx完成环境切换。<br><img src="/assets/blogImg/nginx1.jpg" alt=""></p>
<p>切换环境，如今只需点击一次。</p>
<h3 id="场景二：SourceMap"><a href="#场景二：SourceMap" class="headerlink" title="场景二：SourceMap"></a>场景二：SourceMap</h3><p>在线上环境调试Js代码是件麻烦的事情，因为目前合格的前端部署，代码都应经过压缩。性能问题是优化了，debug可不怎么方便。</p>
<p>而SourceMap正好可以解决此问题。</p>
<p>在最新的各版本浏览器里，如果满足：</p>
<ol>
<li>压缩后的js文件后面有<code>//# sourceMappingURL=xxx.map</code>格式的注释</li>
<li>浏览器能正常访问到sourceMappingURL</li>
</ol>
<p>那么，就能把压缩过的代码还原。<br>要实现这样的功能，就必须：</p>
<ol>
<li>现网环境不带以上形式的注释，同时访问不到sourceMap（安全性考虑）</li>
<li>测试环境带注释，能访问sourceMap</li>
</ol>
<p>这样的模型，用<code>反向代理+内容纂改</code>的思路再合适不过。<br>每次构建编译时，我们会把sourceMap文件存放到一台机器（举例为1.1.1.1），命名为js文件名后加<code>.map</code>后缀。随后，使用Nginx，通过这几行配置就能把此功能实现：</p>
<figure class="highlight nginx"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="attribute">location</span> <span class="regexp">~ \.js$</span> &#123;</div><div class="line">    <span class="attribute">footer</span> <span class="string">"\n//# sourceMappingURL=<span class="variable">$request_uri</span>.map"</span>;</div><div class="line">    <span class="attribute">footer_types</span> <span class="string">"*"</span>;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>只要经过代理，在chrome里，我们能看到每份被压缩过的js文件，都有一个对应的源码文件。<br>你可以直接使用它来做打断点之类的操作，大大的提升了调试质量。<br><img src="/assets/blogImg/nginx2.jpg" alt=""></p>
<h3 id="场景三：内容纂改"><a href="#场景三：内容纂改" class="headerlink" title="场景三：内容纂改"></a>场景三：内容纂改</h3><p>其实在以上两个场景里，都涉及了“内容纂改”。<br>无论是说“纂改”还是“劫持”，大家的印象都不是什么好事情，但另一方面，他们又可以让事情有趣起来。</p>
<p>统一介绍下，Nginx涉及纂改的模块有：</p>
<ul>
<li><a href="https://m.oschina.net/blog/156826" target="_blank" rel="external">nginx_http_footer_filter</a>：往文件的底部添加文字，可包含Nginx的内置变量；</li>
<li><a href="http://nginx.org/en/docs/http/ngx_http_addition_module.html" target="_blank" rel="external">nginx_http_addition_module</a>：从一个url去读取内容，将之添加到文件的头部或顶部；</li>
<li><a href="http://nginx.org/en/docs/http/ngx_http_sub_module.html" target="_blank" rel="external">nginx_http_sub_module</a>：替换字符</li>
</ul>
<p>除去上面两种场景，合理运用这些模块对应的配置，可以做出许多小工具，这是很有想象力的事情。<br>单单针对移动web前端开发，就可以实现： </p>
<blockquote>
<ol>
<li>将<a href="http://people.apache.org/~pmuellr/weinre-docs/latest/" target="_blank" rel="external">weinre</a>脚本插入到html里，让移动web调试更加便捷。</li>
<li>移动web经常用到localStorage优化首屏，但debug时又会受到干扰，通过一个按钮很方便的清除本地缓存。</li>
<li>手机APP内嵌页面，很难将其网址分享给另一个人。通过一个按钮就能生成url对应的二维码等</li>
</ol>
</blockquote>
<h3 id="场景四：本地映射"><a href="#场景四：本地映射" class="headerlink" title="场景四：本地映射"></a>场景四：本地映射</h3><p>在Windows下的前端抓包调试，Fiddler+Willow的能力毋庸置疑。<br>而脱离了.NET体系的Linux和Mac，即使有一些代替工具，但某些方面还是略显不足。   </p>
<p>比如：<strong>线上接口映射到本地文件</strong>。<br>想到Fiddler的本质也是一个代理，而开启一个有这样能力的Nginx服务，并不是太难的事情。           </p>
<p>而且，我们可以做得更灵活，比如：</p>
<ul>
<li>同时支持慢速调试</li>
<li>同时支持目录层级映射</li>
<li>同时支持正则匹配</li>
<li>JSON返回的数据有可能是变化的（比如分页时候），同时支持动态数据</li>
</ul>
<p>这些场景，只运用到Nginx里的“<a href="http://www.linuxidc.com/Linux/2014-01/95493.htm" target="_blank" rel="external">rewrite规则</a>”。<br>从参考的文档可以大致看到，rewrite规则非常灵活，能完成各种场景的转发。 </p>
<p>最简单的模型中，我们把所有带<code>cgi-bin</code>路径的请求，rewite到本地的一个服务，同时带上请求的所有参数，<br>仅需这三行配置即可：<br><figure class="highlight nginx"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="attribute">location</span> <span class="regexp">~ /cgi-bin/*</span> &#123;</div><div class="line">    <span class="attribute">rewrite</span><span class="regexp"> ^(.*)$</span> http://127.0.0.1:8080/cgi-bin/ <span class="literal">last</span>;</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>后续的事情，可以在本地创建一个cgi-bin文件夹，在里面放置需要映射的文本，并开启服务到8080端口即可。 </p>
<h3 id="场景五：移动侧调试"><a href="#场景五：移动侧调试" class="headerlink" title="场景五：移动侧调试"></a>场景五：移动侧调试</h3><p><code>Fiddler</code> 有一个勾选项 <code>Allow remote computers to connect</code>，并可以指定 <code>listen port</code> 可以使得手机/其它终端通过将本机设为代理而访问本机环境，与 <code>hosts</code> 配合会很实用。</p>
<p>这个功能，用Nginx也很容易做到。<br>通过 <code>default_server</code> 作为代理，手机终端通过设置网络代理为本机IP和相应的 <code>listen port</code>，从而可以访问本机的 Web 服务。</p>
<p>其中也是用到了<a href="http://nginx.org/en/docs/http/ngx_http_proxy_module.html" target="_blank" rel="external">ngx_http_proxy_module</a>模块的配置：<br><figure class="highlight nginx"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div></pre></td><td class="code"><pre><div class="line"> <span class="section">server</span> &#123;</div><div class="line">    <span class="attribute">listen</span>  <span class="number">80</span> default_server;</div><div class="line">    <span class="attribute">server_name</span>  localhost;</div><div class="line">    <span class="attribute">resolver</span> <span class="number">8.8.8.8</span>;</div><div class="line">    <span class="attribute">location</span> / &#123;</div><div class="line">        <span class="attribute">proxy_set_header</span> Host <span class="variable">$host</span>;</div><div class="line">        <span class="attribute">proxy_set_header</span> X-Real-Ip <span class="variable">$remote_addr</span>;</div><div class="line">        <span class="attribute">proxy_set_header</span> X-Forwarded-For <span class="variable">$remote_addr</span>;</div><div class="line">        <span class="attribute">proxy_pass</span> http://<span class="variable">$host</span>;</div><div class="line">    &#125;</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="section">server</span> &#123;</div><div class="line">    <span class="attribute">listen</span>  <span class="number">80</span>;</div><div class="line">    <span class="attribute">server_name</span>  ke.qq.com;</div><div class="line">    <span class="attribute">location</span> / &#123;</div><div class="line">        <span class="attribute">proxy_set_header</span> Host <span class="variable">$host</span>;</div><div class="line">        <span class="attribute">proxy_set_header</span> X-Real-Ip <span class="variable">$remote_addr</span>;</div><div class="line">        <span class="attribute">proxy_set_header</span> X-Forwarded-For <span class="variable">$remote_addr</span>;</div><div class="line">        <span class="attribute">proxy_pass</span> http://127.0.0.1:9091/;</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<h3 id="边角料"><a href="#边角料" class="headerlink" title="边角料"></a>边角料</h3><p>除去特定场景，Nginx的一些配置也跟前端息息相关。以下简单罗列，作为边角材料。</p>
<p>1.<a href="https://github.com/alibaba/nginx-http-concat" target="_blank" rel="external">nginx_http_concat</a><br>资源合并，处理CDN combo。例如通过这样的方式<code>http://example.com/??style1.css,style2.css,foo/style3.css</code>访问合并后的资源。</p>
<p>2.<a href="http://nginx.org/en/docs/http/ngx_http_image_filter_module.html" target="_blank" rel="external">ngx_http_image_filter_module</a><br>图片处理。提供图片缩放，jpg压缩，旋转等特性。</p>
<p>3.适配PC与移动web<br>总体可运用<a href="http://nginx.org/en/docs/http/ngx_http_proxy_module.html" target="_blank" rel="external">ngx_http_proxy_module</a>，去实现路径转发。判断平台类型的Nginx配置，在开源项目<a href="http://detectmobilebrowsers.com/" target="_blank" rel="external">detectmobilebrowsers</a>中可以找到。</p>
<h3 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h3><p>学习Nginx，我本身只是出于开开眼界的目的。而的确发现了一些很有启发性的特质。<br>于前端开发，无论线上线下，熟练掌握基本配置，可以做出许多提高效率的工具。<br><strong>但既然是工具，熟手就好</strong>。 </p>
<p>比如Fiddler直观，但Nginx更底层，更灵活，应当按照实际选择即可。</p>
<p>话说回来，后来心情有些惆怅。<br>想起之前，我用NodeJs写过一个八百行的本地调试服务，如今更习惯用Nginx的几行配置。<br>不过我又想，<strong>既然我已经花了时间去写，为什么还要花时间去用？！</strong> </p>
<p>心情又好起来了。（等等有什么不对，管它呢…）</p>
<hr>
<p>END.<br>15.11.03 Litten.</p>

      

      
        <div class="page-reward">
          <a href="javascript:;" class="page-reward-btn tooltip-top">
            <div class="tooltip tooltip-east">
            <span class="tooltip-item">
              赏
            </span>
            <span class="tooltip-content">
              <span class="tooltip-text">
                <span class="tooltip-inner">
                  <p class="reward-p"><i class="icon icon-quo-left"></i>谢谢你请我吃糖果<i class="icon icon-quo-right"></i></p>
                  <div class="reward-box">
                    
                    <div class="reward-box-item">
                      <img class="reward-img" src="/assets/img/alipay.jpg">
                      <span class="reward-type">支付宝</span>
                    </div>
                    
                    
                    <div class="reward-box-item">
                      <img class="reward-img" src="/assets/img/weixin.jpg">
                      <span class="reward-type">微信</span>
                    </div>
                    
                  </div>
                </span>
              </span>
            </span>
          </div>
          </a>
        </div>
      
    </div>
    <div class="article-info article-info-index">
      
      
	<div class="article-tag tagcloud">
		<i class="icon-price-tags"></i>
		<ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/前端/">前端</a></li></ul>
	</div>

      

      

      
        
<div class="share-btn share-icons tooltip-left">
  <div class="tooltip tooltip-east">
    <span class="tooltip-item">
      <a href="javascript:;" class="share-sns share-outer">
        <i class="icon icon-share"></i>
      </a>
    </span>
    <span class="tooltip-content">
      <div class="share-wrap">
        <div class="share-icons">
          <a class="weibo share-sns" href="javascript:;" data-type="weibo">
            <i class="icon icon-weibo"></i>
          </a>
          <a class="weixin share-sns wxFab" href="javascript:;" data-type="weixin">
            <i class="icon icon-weixin"></i>
          </a>
          <a class="qq share-sns" href="javascript:;" data-type="qq">
            <i class="icon icon-qq"></i>
          </a>
          <a class="douban share-sns" href="javascript:;" data-type="douban">
            <i class="icon icon-douban"></i>
          </a>
          <a class="qzone share-sns" href="javascript:;" data-type="qzone">
            <i class="icon icon-qzone"></i>
          </a>
          <a class="facebook share-sns" href="javascript:;" data-type="facebook">
            <i class="icon icon-facebook"></i>
          </a>
          <a class="twitter share-sns" href="javascript:;" data-type="twitter">
            <i class="icon icon-twitter"></i>
          </a>
          <a class="google share-sns" href="javascript:;" data-type="google">
            <i class="icon icon-google"></i>
          </a>
        </div>
      </div>
    </span>
  </div>
</div>

<div class="page-modal wx-share js-wx-box">
    <a class="close js-modal-close" href="javascript:;"><i class="icon icon-close"></i></a>
    <p>扫一扫，分享到微信</p>
    <div class="wx-qrcode">
      <img src="" alt="微信分享二维码">
    </div>
</div>

<div class="mask js-mask"></div>
      
      <div class="clearfix"></div>
    </div>
  </div>
</article>

  
<nav id="article-nav">
  
    <a href="/2016/01/04/the-storied-life-of-aj/" id="article-nav-newer" class="article-nav-link-wrap">
      <i class="icon-circle-left"></i>
      <div class="article-nav-title">
        
          从《岛上书店》说开去
        
      </div>
    </a>
  
  
    <a href="/2015/07/06/hack-in-localstorage/" id="article-nav-older" class="article-nav-link-wrap">
      <div class="article-nav-title">作为一个前端，可以如何机智地弄坏一台电脑？</div>
      <i class="icon-circle-right"></i>
    </a>
  
</nav>






<div class="duoshuo">
	<!-- 多说评论框 start -->
	<div class="ds-thread" data-thread-key="nginx-in-fe" data-title="Nginx能为前端开发带来什么？" data-url="//litten.me/2015/11/03/nginx-in-fe/"></div>
	<!-- 多说评论框 end -->
	<!-- 多说公共JS代码 start (一个网页只需插入一次) -->
	<script type="text/javascript">
	var duoshuoQuery = {short_name:"litten-hexo"};
	(function() {
		var ds = document.createElement('script');
		ds.type = 'text/javascript';ds.async = true;
		ds.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') + '//static.duoshuo.com/embed.js';
		ds.charset = 'UTF-8';
		(document.getElementsByTagName('head')[0] 
		 || document.getElementsByTagName('body')[0]).appendChild(ds);
	})();
	</script>
	<!-- 多说公共JS代码 end -->
</div>





          </div>
        </div>
      </div>
      <footer id="footer">
  <div class="outer">
    <div id="footer-info">
    	<div class="footer-left">
    		&copy; 2016 Litten
    	</div>
      	<div class="footer-right">
      		<a href="http://hexo.io/" target="_blank">Hexo</a>  Theme <a href="https://github.com/litten/hexo-theme-yilia" target="_blank">Yilia</a> by Litten
      	</div>
    </div>
  </div>
</footer>
    </div>
    <script>
	var yiliaConfig = {
		mathjax: false,
		isHome: false,
		isPost: true,
		isArchive: false,
		isTag: false,
		isCategory: false,
		open_in_new: true,
		root: "/",
		innerArchive: true
	}
</script>

<script src="/./main.js?v=4.0.0.js"></script>


    
<div class="tools-col" q-class="show:isShow,hide:isShow|isFalse" q-on="click:stop(e)">
  <div class="tools-wrap">
    
    	<section class="tools-section tools-section-all" q-show="innerArchive">
        <div class="search-wrap">
          <input class="search-ipt" q-model="search" type="text" placeholder="find something…">
          <i class="icon-search icon" q-show="search|isEmptyStr"></i>
          <i class="icon-close icon" q-show="search|isNotEmptyStr" q-on="click:clearChose(e)"></i>
        </div>
        <div class="widget tagcloud search-tag">
          <p class="search-tag-wording">tag:</p>
          <label class="search-switch">
            <input type="checkbox" q-on="click:toggleTag(e)" q-attr="checked:showTags">
          </label>
          <ul class="article-tag-list" q-show="showTags">
             
              <li class="article-tag-list-item">
                <a href="javascript:void(0)">js</a>
              </li>
             
              <li class="article-tag-list-item">
                <a href="javascript:void(0)">html5</a>
              </li>
             
              <li class="article-tag-list-item">
                <a href="javascript:void(0)">设计</a>
              </li>
             
              <li class="article-tag-list-item">
                <a href="javascript:void(0)">杂谈</a>
              </li>
             
              <li class="article-tag-list-item">
                <a href="javascript:void(0)">游戏</a>
              </li>
             
              <li class="article-tag-list-item">
                <a href="javascript:void(0)">旧事</a>
              </li>
             
              <li class="article-tag-list-item">
                <a href="javascript:void(0)">coffeescript</a>
              </li>
             
              <li class="article-tag-list-item">
                <a href="javascript:void(0)">web</a>
              </li>
             
              <li class="article-tag-list-item">
                <a href="javascript:void(0)">旅行</a>
              </li>
             
              <li class="article-tag-list-item">
                <a href="javascript:void(0)">css</a>
              </li>
             
              <li class="article-tag-list-item">
                <a href="javascript:void(0)">css3</a>
              </li>
             
              <li class="article-tag-list-item">
                <a href="javascript:void(0)">工具</a>
              </li>
             
              <li class="article-tag-list-item">
                <a href="javascript:void(0)">chrome</a>
              </li>
             
              <li class="article-tag-list-item">
                <a href="javascript:void(0)">生活</a>
              </li>
             
              <li class="article-tag-list-item">
                <a href="javascript:void(0)">安全</a>
              </li>
             
              <li class="article-tag-list-item">
                <a href="javascript:void(0)">黑科技</a>
              </li>
             
              <li class="article-tag-list-item">
                <a href="javascript:void(0)">octopress</a>
              </li>
             
              <li class="article-tag-list-item">
                <a href="javascript:void(0)">浏览器</a>
              </li>
             
              <li class="article-tag-list-item">
                <a href="javascript:void(0)">主题</a>
              </li>
             
              <li class="article-tag-list-item">
                <a href="javascript:void(0)">hexo</a>
              </li>
             
              <li class="article-tag-list-item">
                <a href="javascript:void(0)">经验</a>
              </li>
             
              <li class="article-tag-list-item">
                <a href="javascript:void(0)">产品</a>
              </li>
             
              <li class="article-tag-list-item">
                <a href="javascript:void(0)">前端</a>
              </li>
             
              <li class="article-tag-list-item">
                <a href="javascript:void(0)">github</a>
              </li>
             
              <li class="article-tag-list-item">
                <a href="javascript:void(0)">药别停</a>
              </li>
             
              <li class="article-tag-list-item">
                <a href="javascript:void(0)">模式</a>
              </li>
             
              <li class="article-tag-list-item">
                <a href="javascript:void(0)">性能</a>
              </li>
            
            <div class="clearfix"></div>
          </ul>
        </div>
        <ul class="search-ul">
          <p q-show="jsonFail" style="padding: 20px; font-size: 12px;">
            缺失模块。<br/>1、在博客根目录（注意不是yilia根目录）执行以下命令：<br/> npm i hexo-generator-json-content --save<br/><br/>
            2、在根目录_config.yml里添加配置：
<pre style="font-size: 12px;" q-show="jsonFail">
  jsonContent:
    meta: false
    pages: false
    posts:
      title: true
      date: true
      path: true
      text: true
      raw: false
      content: false
      slug: false
      updated: false
      comments: false
      link: false
      permalink: false
      excerpt: false
      categories: false
      tags: true
</pre>
          </p>
          <li class="search-li" q-repeat="items" q-show="isShow">
            <a q-attr="href:path|urlformat" class="search-title"><i class="icon-quo-left icon"></i><span q-text="title"></span></a>
            <p class="search-time">
              <i class="icon-calendar icon"></i>
              <span q-text="date|dateformat"></span>
            </p>
            <p class="search-tag">
              <i class="icon-price-tags icon"></i>
              <span q-repeat="tags" q-on="click:choseTag(e, name)" q-text="name|tagformat"></span>
            </p>
          </li>
        </ul>
    	</section>
    

    

    
    	<section class="tools-section tools-section-me" q-show="aboutme">
  	  	
  	  		<div class="aboutme-wrap" id="js-aboutme">Litten，&lt;br&gt;毕业于华科，就职于鹅厂&lt;br&gt;&lt;br&gt;热爱大海与冷笑话，&lt;br/&gt;目前是一枚前端&lt;br/&gt;&lt;br/&gt;胆小认生，不易相处，&lt;br&gt;年轻无为，卖马为生。</div>
  	  	
    	</section>
    
  </div>
  
</div>
    <!-- Root element of PhotoSwipe. Must have class pswp. -->
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">

    <!-- Background of PhotoSwipe. 
         It's a separate element as animating opacity is faster than rgba(). -->
    <div class="pswp__bg"></div>

    <!-- Slides wrapper with overflow:hidden. -->
    <div class="pswp__scroll-wrap">

        <!-- Container that holds slides. 
            PhotoSwipe keeps only 3 of them in the DOM to save memory.
            Don't modify these 3 pswp__item elements, data is added later on. -->
        <div class="pswp__container">
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
        </div>

        <!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
        <div class="pswp__ui pswp__ui--hidden">

            <div class="pswp__top-bar">

                <!--  Controls are self-explanatory. Order can be changed. -->

                <div class="pswp__counter"></div>

                <button class="pswp__button pswp__button--close" title="Close (Esc)"></button>

                <button class="pswp__button pswp__button--share" style="display:none" title="Share"></button>

                <button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>

                <button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>

                <!-- Preloader demo http://codepen.io/dimsemenov/pen/yyBWoR -->
                <!-- element will get class pswp__preloader--active when preloader is running -->
                <div class="pswp__preloader">
                    <div class="pswp__preloader__icn">
                      <div class="pswp__preloader__cut">
                        <div class="pswp__preloader__donut"></div>
                      </div>
                    </div>
                </div>
            </div>

            <div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
                <div class="pswp__share-tooltip"></div> 
            </div>

            <button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
            </button>

            <button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
            </button>

            <div class="pswp__caption">
                <div class="pswp__caption__center"></div>
            </div>

        </div>

    </div>

</div>
  </div>
</body>
</html>